/*
	Visp is an opensource visual performance application built with Adobe® AIR™.
	Copyright (C) 2007 Mike Creighton
	
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
	
	Mike Creighton can be found at http://www.mikecreighton.com		
*/
package
{
	import com.visp.constants.OutputSize;
	import com.visp.constants.RendererBang;
	import com.visp.events.BangEvent;
	import com.visp.events.DisplayMouseEvent;
	import com.visp.events.LifecycleEvent;
	import com.visp.events.RangeEvent;
	import com.visp.render.IRenderable;
	
	import flash.display.Sprite;
	import flash.geom.ColorTransform;
	
	import mx.collections.ArrayCollection;
	import mx.effects.AnimateProperty;
	import mx.effects.easing.Linear;
	import mx.events.EffectEvent;
	import com.visp.constants.RendererRange;
	
	public class BursterRenderer extends Sprite implements IRenderable
	{
		private var _currentColor : int;
		private var _currentColorSet : ColorSet;
		private var _colors : ArrayCollection;
		
		private var _bgs : ArrayCollection;
		private var _lastRotationRatio : Number;
		private var _constructs : ArrayCollection;
		private var _lastFadeDuration : Number;
		
		public function BursterRenderer()
		{
			super();
			
			this._lastRotationRatio = 0.0;
			this._constructs = new ArrayCollection();
			
			this._lastFadeDuration = 0.5;
			this._currentColor = -1;
			
			// Create a bunch of colors (foreground and gradient fills)
			this._colors = new ArrayCollection();
			this._colors.addItem(new ColorSet(0xFFCAA293, 0xFFD2AEA1, 0xFF42251E));
			this._colors.addItem(new ColorSet(0xFF4C2119, 0xFF421D16, 0xFFEA6149));
			this._colors.addItem(new ColorSet(0xFFf5e9b3, 0xFFb5a815, 0xFF304449));
			this._colors.addItem(new ColorSet(0xFF576012, 0xFFb5a815, 0xFFfaecbc));
			this._colors.addItem(new ColorSet(0xFF69a290, 0xFF311155, 0xFF34f2de));
			this._colors.addItem(new ColorSet(0xFF79250f, 0xFFfe8888, 0xFF365b57));
			this._colors.addItem(new ColorSet(0xFF6f6f6f, 0xFFbbdddd, 0xFF713263));
			this._colors.addItem(new ColorSet(0xFFeedca1, 0xFF619293, 0xFF6c7b4b));
			this._colors.addItem(new ColorSet(0xFF765307, 0xFF3b442d, 0xFFf859ac));
			this._colors.addItem(new ColorSet(0xFF928b7c, 0xFF113a52, 0xFFdcbc97));
			this._colors.addItem(new ColorSet(0xFF18120b, 0xFF1a6b61, 0xFF9c9760));
			this._colors.addItem(new ColorSet(0xFF276579, 0xFF453e30, 0xFFb08099));
			this._bgs = new ArrayCollection();
		}
		
		public function start():void
		{
			this._currentColorSet = this._getNewColorSet();
			this._newBG(this._currentColorSet);
		}
		
		public function destroy():void
		{
		}
		
		public function halt():void { }
		
		public function handleMouseEvent(e:DisplayMouseEvent):void { }
		
		public function handleBangOn(e:BangEvent):void
		{
			/**
			 * Create a new Construct and pass in the velocity of the Bang
			 * so that it affects the size of the individual Structures that
			 * are created.
			 */
			switch(e.id){
				case RendererBang.ID_0:
					var c : Construct = new Construct();
					var o : Object = BursterRenderer._convertHexToARGB(this._currentColorSet.fore);
					c.transform.colorTransform = new ColorTransform(1, 1, 1, 1, o.red, o.green, o.blue, 0);
					c.addEventListener(LifecycleEvent.DESTROYED, this._handleConstructDestroyed);
					c.x = OutputSize.WIDTH / 2;
					c.y = OutputSize.HEIGHT / 2;
					this.addChild(c);
					this._constructs.addItem(c);
					c.explode(e.velocity, this._lastRotationRatio);
				break;
				
				/**
				 * Destroy the current constructs on-screen.
				 */
				case RendererBang.ID_1:
					var i : int = this._constructs.length;
					while(i--){
						var con : Construct = this._constructs.getItemAt(i) as Construct;
						if(!con.isDestroying){
							con.destroy();
						}
					}
				break;
				
				/**
				 * Issue a change of the current color set.
				 */
				case RendererBang.ID_2:
					this._currentColorSet = this._getNewColorSet();
					this._newBG(this._currentColorSet);
				break;
			}
		}
		
		public function handleBangOff(e:BangEvent):void { }
		
		public function handleRange(e:RangeEvent):void
		{
			switch(e.id){
				/**
				 * Use the 1st Range Input to adjust the rotation speed.
				 * .5 means that no rotation happens. Plus or minus that
				 * value will rotate the constructs clockwise or counter-
				 * clockwise.
				 */
				case RendererRange.ID_0:
					this._lastRotationRatio = e.value - .5;
					var i : int = this._constructs.length;
					while(i--){
						var c : Construct = this._constructs.getItemAt(i) as Construct;
						if(!c.isDestroying){
							c.updateRotationSpeed(this._lastRotationRatio);
						}
					}
				break;
				
				/**
				 * Use the 2nd slider to adjust the duration of the new background
				 * fade-in request.
				 */
				case RendererRange.ID_1:
					this._lastFadeDuration = e.value;
				break;
				
			}
		}
		
		private function _getNewColorSet() : ColorSet
		{
			var i : int
			if(this._colors.length > 1){
				do{
					i = Math.floor(Math.random() * this._colors.length);
				} while (i == this._currentColor);
				this._currentColor = i;
			} else {
				this._currentColor = 0;
			}
			return this._colors.getItemAt(this._currentColor) as ColorSet;
		}
		
		private function _newBG(c : ColorSet) : void
		{			
			var g : CircGradBG = new CircGradBG(c.grad1, c.grad2);
			this._bgs.addItem(g);
			g.alpha = 0;
			
			var ani : AnimateProperty = new AnimateProperty(g);
			ani.property = "alpha";
			ani.duration = this._lastFadeDuration * 5000;
			ani.fromValue = 0;
			ani.toValue = 1;
			ani.easingFunction = Linear.easeNone;
			ani.play();
			
			this.addChild(g);
			
			// Fade out the old one.
			if(this._bgs.length > 1){
				var old : CircGradBG = this._bgs.getItemAt(this._bgs.length - 2) as CircGradBG;
				var out : AnimateProperty = new AnimateProperty(old);
				out.addEventListener(EffectEvent.EFFECT_END, this._handleBgDone);
				out.property = "alpha";
				out.duration = this._lastFadeDuration * 5000;
				out.fromValue = old.alpha;
				out.startDelay = out.duration;
				out.toValue = 0;
				out.easingFunction = Linear.easeNone;
				out.play();
			}
		}
		
		private function _handleBgDone(e : EffectEvent) : void
		{
			var i : int = this._bgs.length;
			var bg : CircGradBG;
			while(i--){
				bg = this._bgs.getItemAt(i) as CircGradBG;
				if(bg.alpha == 0){
					this._bgs.removeItemAt(i);
					this.removeChild(bg);
				}
			}
		}
		
		private function _handleConstructDestroyed(e : LifecycleEvent) : void
		{
			var c : Construct = (e.target as Construct);
			c.removeEventListener(LifecycleEvent.DESTROYED, this._handleConstructDestroyed);
			var index : int = this._constructs.getItemIndex(c);
			this._constructs.removeItemAt(index);
			this.removeChild(c);
		}
		
		private static function _convertHexToARGB( val : uint ) : Object
		{
		    var col : Object = new Object();
		    col.alpha = (val >> 24) & 0xFF;
		    col.red = (val >> 16) & 0xFF;
		    col.green = (val >> 8) & 0xFF;
		    col.blue = val & 0xFF;
		    return col;
		}
	}
}